﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;

namespace SoulDoorEngine.Framework.Services
{
    public class SEServiceContainer : IServiceProvider
    {
        private Dictionary<Type, object> _Services = new Dictionary<Type, object>();

        /// <summary>
        /// 包含服务类型与服务提供者的目录
        /// </summary>
        private Dictionary<Type,object> Services
        {
            get { return _Services; }
            set { _Services = value; }
        }

        /// <summary>
        /// 增加一项新服务，若服务容器内已经拥有该服务则抛出异常
        /// </summary>
        /// <param name="service">增加的服务类型</param>
        /// <param name="provider">增加的服务提供者</param>
        public void AddService(Type service, object provider)
        {
            if (this.Services.ContainsKey(service))
            {
                throw new Exception("该服务容器内已经拥有一个类型为" + service.Name + "的服务提供者了");
            }

            this.Services.Add(service, provider);
        }
        
        /// <summary>
        /// 通过服务类型获取服务，继承IServiceProvider接口必须实现提供简便版本函数 T GetService<T>()
        /// </summary>
        /// <param name="serviceType">需要获取服务的类型</param>
        /// <returns></returns>
        public object GetService(Type serviceType)
        {
            foreach (Type item in this.Services.Keys)
            {
                if (item == serviceType)
                {
                    return this.Services[item];
                }
            }

            throw new Exception("该服务容器内不包含类型为" + serviceType.Name + "的服务提供者");
        }

        /// <summary>
        /// 通过上下文提供简便版本获取服务
        /// </summary>
        /// <typeparam name="T">需要获取服务的类型</typeparam>
        /// <returns></returns>
        public T GetService<T>()
        {
            //对于"Camera cam = (Camera)Services.GetService(typeof(Camera));",
            //我们可以用"Camera cam = Services.GetService()"代替
            object result = GetService(typeof(T));
            if (result != null)
            {
                return (T)result;
            }

            //关于default:因为不清楚T是值类型（int等）还是引用类型（string等），default可在前者返回0，后者返回null
            return default(T);
        }

        /// <summary>
        /// 移除一项服务，若不存在则不发生变化
        /// </summary>
        /// <param name="service">将要移除的服务类型</param>
        public void RemoveService(Type service)
        {
            if (this.Services.ContainsKey(service))
            {
                this.Services.Remove(service);
            }
        }

        /// <summary>
        /// 获知服务容器内是否存在该类型的服务
        /// </summary>
        /// <param name="service">服务类型</param>
        /// <returns></returns>
        public bool ContainService(Type service)
        {
            return this.Services.ContainsKey(service);
        }

        /// <summary>
        /// 重置服务容器中的服务，除了GraphicsDeviceService
        /// </summary>
        public void Clear()
        {
            List<Type> toRemove = new List<Type>();

            //注意KeyValuePair为结构体
            foreach (KeyValuePair<Type,object> item in this.Services)
            {
                toRemove.Add(item.Key);
            }

            foreach (Type item in toRemove)
            {
                if (item != typeof(IGraphicsDeviceService))
                {
                    Services.Remove(item);
                }
            }
        }

        public bool IsService(object provider, out Type serviceType)
        {
            if (this.Services.ContainsValue(provider))
            {
                //无法通过value索引key，必须遍历
                foreach (KeyValuePair<Type,object> item in this.Services)
                {
                    if (item.Value == provider)
                    {
                        serviceType = item.Key;
                        return true;
                    }
                }
            }

            serviceType = null;
            return false;
        }
    }
}
